package com.java.mall_imooc.listener;

import cn.hutool.json.JSONUtil;
import com.java.mall_imooc.entity.PayInfo;
import com.java.mall_imooc.service.OrderService;
import com.lly835.bestpay.enums.OrderStatusEnum;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.io.IOException;

/**
 * @author jiangli
 * @since 2020-03-17 22:24
 */
@Component
@Slf4j
public class PayMsgListener {
    @Value("${spring.rabbitmq.listener.simple.retry.max-attempts}")
    private int mqRetryCount;
    @Autowired
    private OrderService orderService;

    /**
     * 监听订单消息
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = "imooc.order.pay.queue", durable = "true"),
            exchange = @Exchange(
                    value = "${spring.rabbitmq.template.exchange:imooc.exchange}",  // 没有就用yml中配置的默认的exchange
                    ignoreDeclarationExceptions = "true",
                    type = ExchangeTypes.TOPIC),
            key = {"order.pay"}
    ))
    public void process(String payInfoStr, Channel channel, Message message) {
        // 参数校验
        Assert.notNull(payInfoStr, "消息体不能为NULL");
        log.info("[接收到消息:{}]", payInfoStr);
        try {
            PayInfo payInfo = JSONUtil.toBean(payInfoStr, PayInfo.class);
            if (OrderStatusEnum.SUCCESS.name().equals(payInfo.getPlatformStatus())) {
                // 修改订单状态
                orderService.paid(Long.valueOf(payInfo.getOrderNo()));
            }
            // 确认消息已经消费成功
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            // 消费失败后重新入队
            try {
                //拒绝deliveryTag对应的消息，第二个参数是否应用于多消息，第三个参数是否requeue:true则重新入队列，否则丢弃或者进入死信队列
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,true);
            } catch (IOException ex) {
                log.error("MQ消息重新入队异常，消息体:{}", payInfoStr, ex);
            }
            log.error("MQ消息处理异常，消息体:{}", payInfoStr, e);
        }

    }
}
